import {HandleModel} from "../model1/HandleModel";
import {PlayerDataKey, PlayerSourceData, UnitDataKey} from "../../../dataSource/DataSource";
import Configer from "../../config/Configer";
import {LocModel} from "../../base/LocModel";
import {UnitModel} from "../model3/UnitModel";
import {RectModel} from "../model2/RectModel";
import {AbilityJson, PlayerJson} from "../../model/StoreJson";
import {ConfigKey} from "../../../../constant/ConfigConstant";
import MathUtil from "../../../codeAdapter/MathUtil";
import {GlobalModel} from "../model1/GlobalModel";
import {CodeUtil} from "../../../codeAdapter/CodeUtil";
import {IPlayerAdapter, playerAdapter} from "../../adapter/adapterInterface/model4/IPlayerAdapter";
import {Logger} from "../../config/Logger";
import {CastType1} from "../../../dataSource/DataModel";
import TimerUtil from "../../../TimerUtil";
import {EffectAnimation} from "../../../../type/Type";
import {ItemModel} from "../model3/ItemModel";

/** @noSelfInFile **/

// const map: WeakMap<handle, any> = new WeakMap<handle, any>();

export class PlayerModel implements HandleModel {

    public data: PlayerSourceData = new PlayerSourceData();
    playerAdapter: IPlayerAdapter;

    public handle: any;
    id: string;
    nikeName: string;


    constructor(index: number, json: PlayerJson) {
        this.nikeName = `${index}`;
        this.playerAdapter = playerAdapter.adapter
        const handle = this.playerAdapter.createHandle(index);
        this.bindHandle(handle);
        this.loadJson(json)
    }

    public isLocalPlayer() {
        return this.playerAdapter.isLocalPlayer(this.handle)
    }

    /**
     * addons
     */
    public displayText(text: string) {
        this.playerAdapter.displayText(this.handle, text);
    }

    //
    // getId () {
    //     return `player_${GetPlayerId(this.handle)}`;
    // }

    public get playerId(): number {
        return this.playerAdapter.getPlayerId(this.handle);
    }

    public clearSelecteds(): void {
        return this.playerAdapter.clearSelected(this.handle);
    }


    public isNeutralHostilityId(): boolean {
        const id = this.playerAdapter.getPlayerId(this.handle);
        const neutralHostilityId = Configer.getConfig(ConfigKey.neutralHostilityId);
        return id === neutralHostilityId;
    }

    public isNeutralInvincibilityId(): boolean {
        const id = this.playerAdapter.getPlayerId(this.handle);
        const neutralInvincibility = Configer.getConfig(ConfigKey.neutralInvincibility);
        return id === neutralInvincibility;
    }

    public get name(): string {
        return this.playerAdapter.getName(this.handle);
    }

    public set name(value: string) {
        this.playerAdapter.setName(this.handle, value);
    }

    public get startLocation() {
        const startLoc = this.data[PlayerDataKey.startLoc];
        if (startLoc) {
            return startLoc;
        }
        const loc = this.playerAdapter.getStartLoc(this.handle);
        return loc;
    }

    public get team() {
        return this.playerAdapter.getTeam(this.handle);
    }

    public coordsFogged(loc: LocModel) {
        return this.playerAdapter.coordsFogged(this.handle, loc);
    }

    public coordsMasked(loc: LocModel) {
        return this.playerAdapter.coordsMasked(this.handle, loc);
    }

    public coordsVisible(loc: LocModel) {
        return this.playerAdapter.coordsVisible(this.handle, loc);
    }

    public removeAllGuardPositions() {
        this.playerAdapter.removeAllGuardPositions(this.handle);
    }

    public toWin() {
       this.playerAdapter.toWin(this.handle);
    }

    public toLose() {
        this.playerAdapter.toLose(this.handle);
    }

    public cosumeGold(value: number) {
        const currentCoin = this.gold;
        if (currentCoin >= value) {
            this.gold = currentCoin - value
            return true;
        }
        return false;
    }

    public addGold(value: number) {
        const currentCoin = this.gold;
        this.gold = currentCoin + value
        return true;
    }

    public cosumeLumber(value: number) {
        const currentLumber = this.lumber;
        if (currentLumber >= value) {
            this.lumber = currentLumber - value
            return true;
        }
        return false;
    }

    public addLumber(value: number) {
        const currentLumber = this.lumber;
        this.lumber = currentLumber + value
        return true;
    }

    public get gold(): number {
        return this.playerAdapter.getGold(this.handle);
    }
    public set gold(value: number) {
        this.playerAdapter.setGold(this.handle, value);
    }


    public get lumber(): number {
        return this.playerAdapter.getLumber(this.handle);
    }

    public set lumber(value: number) {
        this.playerAdapter.setLumber(this.handle, value);
    }

    public get allFood(): number {
        return this.playerAdapter.getAllFood(this.handle);
    }

    public set allFood(value: number) {
        this.playerAdapter.setAllFood(this.handle, value);
    }

    public get usedFood(): number {
        return this.playerAdapter.getUsedFood(this.handle);
    }

    public set usedFood(value: number) {
        this.playerAdapter.setUsedFood(this.handle, value);
    }

    public isNotEndPlaying() {
        const isPlaying = this.isPlaying();
        const bLose = !this.data[PlayerDataKey.bLosed];
        return isPlaying && bLose
    }

    public isPlaying() {
        return this.playerAdapter.isPlaying(this.handle);
    }

    public isPlayerAlly(player: PlayerModel) {
        if (player?.isValid()) {
            return this.playerAdapter.isPlayerAlly(this.handle, player.handle);
        }
        return false;
    }

    public setAlly(player: PlayerModel, bool: boolean) {
        return this.playerAdapter.setAlly(this.handle, player.handle, bool);
    }

    public removeFog(rect: RectModel): any {
        return this.playerAdapter.removeFog(this.handle, rect.handle);
    }

    public addFog(fog: any): any {
        return this.playerAdapter.addFog(this.handle,fog);
    }

    public reflushUUId() {
        let str = '';
        const uuidNum = Configer.getConfig(ConfigKey.uuidNum);
        for (let i = 0; i < uuidNum; i ++) {
            const tempNum = this.getRandomInt(0, 9);
            str = `${str}${tempNum}`;
        }
        this.data[PlayerDataKey.uuid] = str;
    }

    public createUserId(time: number, index: number): string {
        let str = '';
        const uuid = this.data[PlayerDataKey.uuid];
        str = `${time}${index}${uuid}`
        this.data[PlayerDataKey.userId] = str;
        return this.data[PlayerDataKey.userId]
    }

    // 给玩家亮小地图信号
    public signal(loc: LocModel) {
        this.playerAdapter.signal(this.handle, loc);
    }

    public setTech(id: string, lv: number) {
        this.playerAdapter.setTech(this.handle, id, lv);
    }
    public getTech(id: string) {
        return this.playerAdapter.getTech(this.handle, id);
    }

    public toBeUnitOwner(unitModel: UnitModel, changeColor: boolean) {
        this.playerAdapter.toBeUnitOwner(this.handle, unitModel, changeColor);
    }

    public setPlayerGoldReward(bool: boolean) {
        this.playerAdapter.setPlayerGoldReward(this.handle, bool);
    }

    public moveUnit(unit: UnitModel, loc: LocModel, andCamera: boolean = true) {
        this.playerAdapter.moveUnit(unit, loc);
        if (andCamera) {
            this.moveCamera(loc, 0);
        }
    }

    public moveCamera(loc: LocModel, duration: number) {
        const height = this.data[PlayerDataKey.cameraHeight];
        this.playerAdapter.moveCamera(this.handle, loc, height, duration);
    }

    public setCameraHeight(height: number) {
        this.data[PlayerDataKey.cameraHeight] = height;
        this.playerAdapter.setCameraHeight(this.handle, height);
    }

    public setCameraAngle(angle: number) {
        this.data[PlayerDataKey.cameraAngle] = angle;
        this.playerAdapter.setCameraAngle(this.handle, angle);
    }

    addCarmeraHeightFun(num: number) {
        const maxCameraHeight: number = Configer.getConfig(ConfigKey.maxCameraHeight);
        const minCameraHeight: number = Configer.getConfig(ConfigKey.minCameraHeight);
        const z = this.data[PlayerDataKey.cameraHeight];
        const newZ = z + num;
        if (num >= 0) {
            if (newZ < maxCameraHeight) {
                this.data[PlayerDataKey.cameraHeight] = newZ;
                this.data[PlayerDataKey.resetCameraLoc] = true;
            } else {
                Logger.toastProduct('已经是最大视野')
            }
        } else {
            if (newZ > minCameraHeight) {
                this.data[PlayerDataKey.cameraHeight] = newZ;
                this.data[PlayerDataKey.resetCameraLoc] = true;
            } else {
                Logger.toastProduct('已经是最小视野')
            }
        }
    }

    public get cameraAngle() {
        return this.data[PlayerDataKey.cameraAngle];
    }

    get cameraLoc () {
        const y = this.playerAdapter.getCameraY(this.handle);
        const x = this.playerAdapter.getCameraX(this.handle);
        const z =this.data[PlayerDataKey.cameraHeight];
        return  new LocModel(x, y, z);
    }

    set cameraLoc (loc: LocModel) {
        this.playerAdapter.setCameraHeight(this.handle, loc.z);

    }

    public getRandomInt(min: number, max: number) {
        if (GlobalModel.bAsync) {
            const random = this.getFakeRandom(min, max, this.data);
            const int = MathUtil.ceil(random);
            return int;
        } else {
            return MathUtil.random(min, max)
        }
    }

    public getRandomReal(min: number, max: number) {
        if (GlobalModel.bAsync) {
            const random = this.getFakeRandom(min, max, this.data);
            return random;
        } else {
            return MathUtil.randomReal(min, max)
        }
    }

    public getFakeRandom(min: number, max: number, data: PlayerSourceData) {
        return this.playerAdapter.getFakeRandom(this.handle, min, max, data);
    }

    public getJson() {
        const json: PlayerJson = { c: this.gold, w: this.lumber, h: this.data[PlayerDataKey.cameraHeight], a: this.cameraAngle };
        return json
    }
    public loadJson(json: PlayerJson) {
        this.setCameraAngle(json.a);
        this.setCameraHeight(json.h);
        this.gold = json.c;
        this.lumber = json.w;
    }

    // 存档相关
    public getStoredString(key: string) {
        return this.playerAdapter.getStoredString(this.handle, key);
    }
    public setStoredString(key: string, value: string, needRes: boolean = true) {
        this.playerAdapter.setStoredString(this.handle, key, value);
        const res = this.getStoredString(key);
        // if (needRes) {
        //     if (res === value) {
        //         return true
        //     }
        //     return false;
        // }
        return true;
    }
    public setRoomList(key: string, value: string) {
        return this.playerAdapter.setRoomList(this.handle, key, value);
    }
    // 商城相关
    public getHasMallItem(key: string) {
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bWhitelist])) {
            return true;
        }
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bBlacklist])) {
            return false
        } else {
            return this.playerAdapter.getHasMallItem(this.handle, key);
        }
    }
    public getMallItemCount(key: string) {
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bWhitelist])) {
            return 1;
        }
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bBlacklist])) {
            return 0
        } else {
            return this.playerAdapter.getMallItemCount(this.handle, key);
        }
    }
    public consumMallItemCount(key: string, num: number) {
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bWhitelist])) {
            return true;
        }
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bBlacklist])) {
            return false
        } else {
            return this.playerAdapter.consumMallItemCount(this.handle, key, num)
        }
    }
    public getMapLevel() {
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bWhitelist])) {
            return 50;
        }
        if (!CodeUtil.isNullOrZero(this.data[PlayerDataKey.bBlacklist])) {
            return 0
        } else {
            const lv = this.playerAdapter.getMapLevel(this.handle);
            if (!CodeUtil.isNullOrZero(lv)) {
                return lv
            }
            return 0
        }
    }

    destroy() {
        this.handle = undefined;
    }

    bindHandle(handle: any) {
        this.playerAdapter.bindHandle(handle)
        this.handle = handle;
        this.id = GlobalModel.getHandleId(this.handle);
    }

    equal(handle: PlayerModel): boolean {
        return this.playerAdapter.equal(this.handle, handle.handle);
    }

    getHandleId(): string {
        return this.id;
    }

    showAbilityEffect (abilityJson: AbilityJson, type: CastType1) {
        const id = abilityJson?.id;
        if (!CodeUtil.isNullOrZero(id)) {
        } else {
            Logger.toastProduct('当前技能为空');
            return;
        }
        this.data[PlayerDataKey.targetSpellInfo].id = id;
        this.data[PlayerDataKey.targetSpellInfo].bShow = true;
        this.data[PlayerDataKey.targetSpellInfo].type = type;
        if (this.isLocalPlayer()) {
            this.data[PlayerDataKey.targetSpellInfo].effect.show = true;
            this.data[PlayerDataKey.targetSpellInfo].effect.setAnimation(EffectAnimation.stand)
        }
    }

    hideAbilityEffect () {
        const id = this.data[PlayerDataKey.targetSpellInfo].id;
        if (!CodeUtil.isNullOrZero(id)) {
            this.data[PlayerDataKey.targetSpellInfo].bShow = false;
            if (this.isLocalPlayer()) {
                this.data[PlayerDataKey.targetSpellInfo].effect.show = false;
            }
        }
    }


    showMoveEffect (loc: LocModel) {
        this.data[PlayerDataKey.moveTargetInfo].bShow = true;
        this.data[PlayerDataKey.moveTargetInfo].time = 1;
        if (this.isLocalPlayer()) {
            this.data[PlayerDataKey.moveTargetInfo].effect.loc = loc;
            this.data[PlayerDataKey.moveTargetInfo].effect.show = true;
            this.data[PlayerDataKey.moveTargetInfo].effect.setAnimation(EffectAnimation.stand)
        }
    }

    hideMoveEffect () {
        if (this.data[PlayerDataKey.moveTargetInfo].bShow) {
            this.data[PlayerDataKey.moveTargetInfo].bShow = false;
            if (this.isLocalPlayer()) {
                this.data[PlayerDataKey.moveTargetInfo].effect.show = false;
            }
        }
    }

    isValid(): boolean {
        return this.playerAdapter.isValid(this.handle);
    }


    addAttackMonster(unit: UnitModel) {
        const handleId = unit.getHandleId();
        this.data[PlayerDataKey.attackMonster][handleId] = 1;
    }
    removeAttackMonster(unit: UnitModel) {
        const attackMonsters = this.data[PlayerDataKey.attackMonster];
        const handleId = unit.getHandleId();
        if (handleId) {
            attackMonsters[handleId] = undefined;
            return true
        }
    }

    addMaxAttackMonsterNum(num: number) {
        const currentNum = this.data[PlayerDataKey.maxAttackNum];
        this.data[PlayerDataKey.maxAttackNum] = currentNum + num;
    }

    getMaxAttackMonsterNum() {
        return this.data[PlayerDataKey.maxAttackNum];
    }

    getAttackMonsterNum() {
        const size = CodeUtil.getObjSize(this.data[PlayerDataKey.attackMonster])
        return size;
    }

    getLastSelectedUnit(): UnitModel {
        return this.data[PlayerDataKey.hero];
    }

    // 该方法需要自己判空
    mapBags(callback: (this: void, item: ItemModel, index: number) => boolean) {
        const maxGoodsBagNum = Configer.getConfig(ConfigKey.maxGoodsBagNum);
        const bag = this.data[PlayerDataKey.goodsBag];

        for (let i = 0; i < maxGoodsBagNum; i++) {
            const item = bag[i];
            const ret = callback(item, i);
            if (ret) {
                break;
            }
        }
    }
}
